/**
 * Created by corbin on 15/9/6.
 *
 */
trait GeneralCode {

  val baseTableCode: String => String = pkg =>
    s"""
package $pkg

/**
* Created by corbin.
*
*/
import java.sql.Timestamp

import org.joda.time.DateTime
import slick.driver.MySQLDriver.api._

abstract class BaseTable[T](_tag: Tag, _schemaName: Option[String], _tableName: String) extends Table[T](_tag, _schemaName, _tableName) {

  def this(tag: Tag, tableName: String) = this(tag, None, tableName)

  implicit val dataTimeColumnType = MappedColumnType.base[DateTime, Timestamp](
    dt => new Timestamp(new DateTime().getMillis), ts => new DateTime(ts.getTime)
  )

  val id = column[String]("id", O.PrimaryKey, O.Length(32, varying = true))

  val created_time = column[Long]("created_time")

  val updated_time = column[Long]("updated_time")
}""".trim

  val baseEntityCode: String => String = pkg =>
    s"""
package $pkg

/**
* Created by corbin.
*
*/
trait BaseEntity {
  def id: Option[String]

  def created_time: Long

  def updated_time: Long
}""".trim


  val pagingCode: String => String = pkg =>
    s"""
package $pkg


/**
* Created by corbin.
*
*/
case class Paging[+T](found: Int, page: Int, offset: Long, items: T, itemsCount: Long) {
  lazy val maxPage = found / itemsCount + (if (found % itemsCount > 0) 1 else 0)

  def parRange(l: Long) = {
    val half = (l - 1) / 2
    val maybeStart: Long = page - half
    //    val maybeEnd=maybeStart +l-1
    def end(maybeEnd: Long) =
    if (maybeEnd < maxPage) maybeEnd else maxPage
    if (maybeStart > 0)
      maybeStart to end(maybeStart + l - 1)
    else 1l to end(l)
  }
}

//case class Page[+T](items: Seq[T], page: Int, offset: Long, total: Long) {
//  lazy val prev = Option(page - 1).filter(_ >= 0)
//  lazy val next = Option(page + 1).filter(_ => (offset + items.size) < total)
//}""".trim


  val MysqlSupport: String => String = pkg =>
    s"""
package $pkg

import slick.backend.DatabaseConfig
import slick.dbio.{DBIOAction, NoStream}
import slick.driver.JdbcProfile
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Await, Future}

/**
* Created by Corbin on 15/7/20.
*
*/

trait MysqlSupport {

  def dbConfig: DatabaseConfig[JdbcProfile]

}

trait MysqlSlickTpl extends MysqlSupport {

  /**Maybe You can init ec use dependency injection */
  //implicit val ec: ExecutionContext = play.api.libs.concurrent.Execution.defaultContext

  def result[R](a: DBIOAction[R, NoStream, Nothing]): R = Await.result(dbConfig.db.run(a), 5.second)

  def async[R](a: DBIOAction[R, NoStream, Nothing]): Future[R] = dbConfig.db.run(a)

}""".trim

val MysqlConfig: String => String = pkg =>
  s"""
package $pkg

/**
* Created by Corbin on 15/8/28.
*
*/

object MysqlConfing {


  val LocalDev =\"\"\"
  |slick.dbs.default.driver = "slick.driver.MySQLDriver$$"
  | slick.dbs.default.db.dataSourceClass = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
  | slick.dbs.default.db.url = "jdbc:mysql://127.0.0.1:3306/dataservice?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=utf8"
  | slick.dbs.default.db.properties.databaseName = "dataservice"
  | slick.dbs.default.db.properties.user = "root"
  | slick.dbs.default.db.properties.password = ""
  | slick.dbs.default.db.numThreads = 10
  | slick.dbs.default.db.connectionTimeout = 5000
  | slick.dbs.default.db.validationTimeout = 5000
  | slick.dbs.default.db.connectionPool = HikariCP //disabled
  | slick.dbs.default.db.cachePrepStmts = true
  | slick.dbs.default.db.prepStmtCacheSize = 250
  | slick.dbs.default.db.prepStmtCacheSqlLimit = 2048\"\"\".stripMargin

}""".trim



 val BaseDao : Option[String] =>String = pkg => {


   val packageName = pkg.map(_+".").getOrElse("")
   s"""
package ${packageName}dao

import ${packageName}models.{BaseEntity, BaseTable}
import slick.driver.MySQLDriver.api._
import ${packageName}support.MysqlSlickTpl

/**
 * Created by corbin
 */

trait BaseDao[T <: BaseTable[E], E <: BaseEntity] extends MysqlSlickTpl {

  /**Maybe you need use transactionally for logic*/

  protected def query = TableQuery[T]

  def returningId = query.returning(query.map(_.id)) //适用于主键id为自增长并且为整数类型

  def all() = async(query.result).map(_.toList)

  def insert(e: E) = async(query insertOrUpdate e)

  def batchInsert(e: E*) = async(query ++= e)

  def apply = { id: String => async(query.filter(_.id === id).result.headOption) }

  def del = { id: String => async(query.filter(_.id === id).delete) }

  def update = { (id: String, e: E) =>
      async(query.filter(_.id === id).update(e))
  }

}
    """.trim
 }


}
